package com.xyzq.cgate.admin.web;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.sun.tools.corba.se.idl.StringGen;
import com.xyzq.cgate.admin.service.RuleService;
import com.xyzq.cgate.admin.wrapper.RuleWrapper;
import com.xyzq.cgate.common.constant.ZkPathConstants;
import com.xyzq.cgate.common.entity.Rule;
import com.xyzq.cgate.common.enums.MatchModeEnum;
import com.xyzq.cgate.common.enums.OpenStateEnum;
import com.xyzq.cgate.common.enums.PluginDetailEnum;
import com.xyzq.cgate.common.enums.RequestTypeEnum;
import com.xyzq.cgate.common.response.ResponseEntity;
import com.xyzq.cgate.common.rule.custom.entity.ComplexRule;
import com.xyzq.cgate.common.rule.custom.entity.RequestData;
import com.xyzq.cgate.common.utils.IdUtil;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author chenchen
 * @since 2019-06-11
 */
@RestController
@RequestMapping("/admin/rule")
public class RuleController {
    @Autowired
    RuleService ruleService;

    @RequestMapping(value = "list", method = RequestMethod.POST)
    public Mono<ResponseEntity> list(@RequestBody RequestData requestData) {
        EntityWrapper entityWrapper = new EntityWrapper();
        entityWrapper.eq("plugin_name", requestData.getPluginName()).orderBy("rule_order");
        List<Rule> list = ruleService.selectList(entityWrapper);
        list.stream().map(r -> RuleWrapper.wrapper(r))
                .collect(Collectors.toList());
        return Mono.just(new ResponseEntity<>().success(list));
    }

    @RequestMapping(value = "create", method = RequestMethod.POST)
    public Mono<ResponseEntity> create(@RequestBody ComplexRule complexRule) throws UnsupportedEncodingException {
        checkComplexRule(complexRule);
        Rule rule = new Rule();
        rule.setId(IdUtil.generateUUID());
        complexRule.setId(rule.getId());
        rule.setPluginName(complexRule.getPluginName());
        rule.setRuleName(complexRule.getRuleName());
        rule.setMatchCondition(JSON.toJSONString(complexRule.getMatchCondition()));
        rule.setLoadBalance(JSON.toJSONString(complexRule.getLoadBalance()));
        rule.setHystrixParam(JSON.toJSONString(complexRule.getHystrixParam()));
        rule.setRuleOrder(Integer.parseInt(complexRule.getRuleOrder()));
        rule.setEnabled(Integer.parseInt(complexRule.getEnabled()));
        rule.setPermitsPerSecond(Optional.ofNullable(complexRule.getPermitsPerSecond()).orElse(""));
        rule.setAppKey(Optional.ofNullable(complexRule.getAppKey()).orElse(""));
        rule.setAppSecret(Optional.ofNullable(complexRule.getAppSecret()).orElse(""));
        rule.setBlackList(Optional.ofNullable(complexRule.getBlackList()).orElse(""));
        rule.setGrayRelease(JSON.toJSONString(complexRule.getGrayRelease()));
        rule.setUniquejson(JSON.toJSONString(complexRule));
        ruleService.insertDbAndZk(rule);
        return Mono.just(new ResponseEntity().success());
    }

    @RequestMapping(value = "switchOpen", method = RequestMethod.POST)
    public Mono<ResponseEntity> switchOpen(@RequestBody Rule rule) throws UnsupportedEncodingException {
        Preconditions.checkNotNull(rule, "rule为null");
        Preconditions.checkNotNull(rule.getId(), "id不能为空");
        rule.setEnabled(1 - rule.getEnabled());
        ComplexRule complexRule = JSON.parseObject(rule.getUniquejson(), ComplexRule.class);
        complexRule.setEnabled("" + rule.getEnabled());
        rule.setUniquejson(JSON.toJSONString(complexRule));
        EntityWrapper<Rule> entityWrapper = new EntityWrapper();
        entityWrapper.eq("id", rule.getId());
        ruleService.updateDbAndZk(rule, entityWrapper);
        return Mono.just(new ResponseEntity<>().success());
    }


    @RequestMapping(value = "delete", method = RequestMethod.POST)
    public Mono<ResponseEntity> delete(@RequestBody Rule rule) throws UnsupportedEncodingException {
        Preconditions.checkNotNull(rule, "rule为null");
        Preconditions.checkNotNull(rule.getId(), "id不能为空");
        EntityWrapper<Rule> entityWrapper = new EntityWrapper();
        entityWrapper.eq("id", rule.getId());
        ruleService.deleteDbAndZk(entityWrapper, rule);
        return Mono.just(new ResponseEntity<>().success());
    }

    @RequestMapping(value = "sync", method = RequestMethod.POST)
    public Mono<ResponseEntity> sync(@RequestBody RequestData requestData) {
        //清除zookeeper数据
        ruleService.removeAllZkDataByParentPath(ZkPathConstants.RULE_PARENT_PATH);
        EntityWrapper entityWrapper = new EntityWrapper();
        entityWrapper.in("plugin_name", Splitter.on(",").trimResults()
                .omitEmptyStrings().splitToList(requestData.getPluginName()));
        List<Rule> list = ruleService.selectList(entityWrapper);
        list.stream().forEach(p -> {
            try {
                ruleService.insertRuleDataToZk(p);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        });
        return Mono.just(new ResponseEntity().success());
    }


    private void checkComplexRule(ComplexRule complexRule) {
        Preconditions.checkNotNull(complexRule);
        Preconditions.checkArgument(StringUtils.isNoneBlank(complexRule.getPluginName()));
        Preconditions.checkArgument(StringUtils.isNoneBlank(complexRule.getRuleName()));
        Preconditions.checkNotNull(complexRule.getMatchCondition());
        Preconditions.checkArgument(StringUtils.isNoneBlank(complexRule.getMatchCondition().getModule())
                        && StringUtils.isNoneBlank(complexRule.getMatchCondition().getMethod())
                        && StringUtils.isNoneBlank(complexRule.getMatchCondition().getQueryType()));
        Preconditions.checkArgument(Arrays.stream(RequestTypeEnum.values())
                        .filter(p -> StringUtils.equalsIgnoreCase(complexRule.getMatchCondition().getQueryType(), "" + p.getRequestType()))
                        .findFirst().isPresent());

        Preconditions.checkNotNull(complexRule.getRuleOrder().matches("\\d+"));
        Preconditions.checkArgument(StringUtils.isNoneBlank(complexRule.getEnabled())
                && Arrays.stream(OpenStateEnum.values())
                .filter(p -> StringUtils.equals(complexRule.getEnabled(), "" + p.getCode()))
                .findFirst().isPresent());

        if(StringUtils.equalsIgnoreCase(complexRule.getPluginName(), PluginDetailEnum.HTTP.getName())) {
            checkComplexRuleForHttp(complexRule);
        } else if(StringUtils.equalsIgnoreCase(complexRule.getPluginName(), PluginDetailEnum.SIGN.getName())) {
            checkComplexRuleForSign(complexRule);
        } else if(StringUtils.equalsIgnoreCase(complexRule.getPluginName(), PluginDetailEnum.FIREWALL.getName())) {
            checkComplexRuleForFireWall(complexRule);
        }  else if(StringUtils.equalsIgnoreCase(complexRule.getPluginName(), PluginDetailEnum.GRAYRELEASE.getName())) {
            checkComplexRuleForGrayRelease(complexRule);
        }
    }

    private void checkComplexRuleForGrayRelease(ComplexRule complexRule) {


    }

    private void checkComplexRuleForFireWall(ComplexRule complexRule) {
        Preconditions.checkArgument(StringUtils.isNoneBlank(complexRule.getBlackList()));
    }

    private void checkComplexRuleForHttp(ComplexRule complexRule) {
        Preconditions.checkNotNull(complexRule.getLoadBalance());
        Preconditions.checkArgument(StringUtils.isNoneBlank(complexRule.getLoadBalance().getRetryTime())
                && StringUtils.isNoneBlank(complexRule.getLoadBalance().getStrategy())
                && complexRule.getLoadBalance().getData().length > 0);
        Preconditions.checkNotNull(complexRule.getHystrixParam());
        Preconditions.checkArgument(StringUtils.isNoneBlank(complexRule.getHystrixParam().getRequestVolumeThreshold())
                && StringUtils.isNoneBlank(complexRule.getHystrixParam().getErrorThresholdPercentage())
                && StringUtils.isNoneBlank(complexRule.getHystrixParam().getSleepWindowInMilliseconds())
                && StringUtils.isNoneBlank(complexRule.getHystrixParam().getTimeoutInMilliseconds())
                && StringUtils.isNoneBlank(complexRule.getHystrixParam().getGroupKey())
                && StringUtils.isNoneBlank(complexRule.getHystrixParam().getCommandKey()));
    }

    private void checkComplexRuleForSign(ComplexRule complexRule) {
        Preconditions.checkArgument(StringUtils.isNoneBlank(complexRule.getAppKey())
                && StringUtils.isNoneBlank(complexRule.getAppSecret()));
    }


/*
    @RequestMapping(value = "update", method = RequestMethod.POST)
    public Mono<ResponseEntity> update(@RequestBody Plugin plugin) {
        Preconditions.checkNotNull(plugin, "plugin为null");
        Preconditions.checkNotNull(plugin.getId(), "id不能为空");
        Preconditions.checkArgument(StringUtils.isNoneBlank(plugin.getName()));
        Preconditions.checkArgument(StringUtils.contains("01", plugin.getRole().toString())
                && StringUtils.contains("01", plugin.getEnabled().toString()));
        plugin.setDateUpdated(new Timestamp(System.currentTimeMillis()));
        EntityWrapper<Plugin> entityWrapper = new EntityWrapper();
        entityWrapper.eq("id", plugin.getId());
        pluginService.update(plugin, entityWrapper);
        return Mono.just(new ResponseEntity<>().success());
    }

    */


}

